package com.emaplink.cryptoutil.sm;

import org.bouncycastle.util.encoders.Hex;
import org.springframework.util.ObjectUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;

public class FileUtilDec {

    // 示例用法
//    static byte[] key = "ZUC_128_Key_1234".getBytes(StandardCharsets.UTF_8);        // ZUC-128: 128位密钥
//    static byte[] iv = "ZUC_IV_123456789".getBytes(StandardCharsets.UTF_8);         // ZUC-128: 128位初始向量

    static byte[]  key = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
            0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
    static  byte[]  iv = new byte[]{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
            0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};

    /**
     * 分段加密文件（可自定义块大小且密钥流根据明文长度动态变化）
     */
    public static void encryptFileInChunks(String sourceFile, String destFile,
                                           byte[] key, byte[] iv, int chunkSize) throws Exception {

        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(destFile);
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {

            byte[] buffer = new byte[chunkSize];
            int bytesRead;
            int totalBytes = 0;

            System.out.println("开始读取文件...");

            while ((bytesRead = bis.read(buffer)) != -1) {
                System.out.println("开始加密文件...");
                // 加密当前块
                byte[] bufferDest = new byte[bytesRead];
                System.arraycopy(buffer, 0, bufferDest, 0, bytesRead);
                byte[] encryptFull = ZUCKeyAppendExample.zuc128Encrypt(key, iv, bufferDest, totalBytes);
                if (encryptFull != null) {
                    bos.write(encryptFull);
                }
                System.out.printf("已处理16进制: "+ Hex.toHexString(encryptFull));
                totalBytes += bytesRead;
                System.out.printf("已处理: %d bytes\n", totalBytes);
            }
            System.out.println("文件加密完成！");
        }
    }

    /**
     * 解密文件 （可自定义解密块大小且密钥流根据密文长度动态变化）
     */
    public static void decryptFileInChunks(String encryptedFile, String decryptedFile,
                                           byte[] key, byte[] iv, int position, int length, int chunkSize) throws Exception {

        try (FileInputStream fis = new FileInputStream(encryptedFile);
             FileOutputStream fos = new FileOutputStream(decryptedFile);
             BufferedInputStream bis = new BufferedInputStream(fis);
             BufferedOutputStream bos = new BufferedOutputStream(fos);
             OutputStreamWriter osw = new OutputStreamWriter(bos, "UTF-8")) {

//            // 读取IV（前16字节）
//            byte[] iv = new byte[16];
//            bis.read(iv);

//            byte[] buffer = new byte[position]; // 解密后数据可能稍大
//            int bytesRead;
//            int totalBytes = position;

            System.out.println("开始读取文件...");

            //正常读取
//            while ((bytesRead = bis.read(buffer)) != -1) {
//                System.out.println("开始解密文件...");
//                byte[] bufferDest = new byte[bytesRead];
//                System.arraycopy(buffer, 0, bufferDest, 0, bytesRead);
//                byte[] partialText = ZUCKeyAppendExample.decryptFromOffset(key, iv, bufferDest, totalBytes);
//                if (partialText != null) {
//                    osw.write(new String(partialText,"UTF-8"));
//                }
//                totalBytes += bytesRead;
//                System.out.printf("已处理: %d bytes\n", totalBytes);
//            }
            //读取指定部分
//            byte[] bufferDest = FileChannelPositionReader.readWithFileChannel(encryptedFile,position,length);
//            byte[] bufferDest = FileChannelPositionReader.readInChunks(encryptedFile,position,length,chunkSize);
            byte[] bufferDest = new byte[length];
            if (ObjectUtils.isEmpty(chunkSize)) {
                bufferDest = FileChannelPositionReader.readWithFileChannel(encryptedFile, position, length);
            } else {
                bufferDest = FileChannelPositionReader.readInChunks(encryptedFile, position, length, chunkSize);
            }
            //解密
            byte[] partialText = ZUCKeyAppendExample.decryptFromOffset(key, iv, bufferDest, position);
            if (partialText != null) {
                osw.write(new String(partialText, "UTF-8"));
            }
            //清理不完整数据
            byte[] cleaned = MessageTruncationHandler.truncateToCompleteCharacters(partialText);
            if (cleaned != null) {
                osw.write("==============>清理不完整数据:" + new String(cleaned, "UTF-8"));
            }
            System.out.println("清理后字节长度: " + cleaned.length + "清理后字节内容: " + new String(cleaned, "UTF-8"));
            System.out.println("文件解密完成！");
        }
    }

    /**
     * 使用 FileOutputStream 创建并写入文件
     */
    public static void writeWithFileOutputStream(String filePath, String content) {
        // 使用 try-with-resources 自动关闭流
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
            fos.write(contentBytes);
            System.out.println("文件创建并写入成功: " + filePath);
        } catch (IOException e) {
            System.err.println("写入文件失败: " + e.getMessage());
        }
    }
    public static void main(String[] args) {
        try {

            String disk = "E";
            String content = "zuccescewaegawrgaergaergharfbaerbaergargvabafrae3234523542634645746";
            //分段读取文件长度
            int chunkSize = 67;
            //从哪个位置开始读取
            int position = 0;
            // 截取数据长度
            int length = 67;
            //type 1:创建明文文件  2:加密文件  3:解密文件  4:分段加密解密文件 其他:创建明文文件并分段加密解密文件
            String type = "5";

            if (args.length > 0) {
                disk = args[0];
                content = args[1];
                chunkSize = Integer.valueOf(args[2]);
                position = Integer.valueOf(args[3]);
                length = Integer.valueOf(args[4]);
                type = args[5];
            }

            String sourceFile = disk + ":\\1.txt";
            String encryptedFile = disk + ":\\2.txt";
            String decryptedFile = disk + ":\\3.txt";

            if ("1".equals(type)) {
                writeWithFileOutputStream(sourceFile, content);
            } else if ("2".equals(type)) {
                encryptFileInChunks(sourceFile, encryptedFile, key, iv, chunkSize);
            } else if ("3".equals(type)) {
                decryptFileInChunks(encryptedFile, decryptedFile, key, iv, position, length,0);
            } else if ("4".equals(type)) {
                encryptFileInChunks(sourceFile, encryptedFile, key, iv, chunkSize);
                decryptFileInChunks(encryptedFile, decryptedFile, key, iv, position, length,chunkSize);
            } else {
                writeWithFileOutputStream(sourceFile, content);
                encryptFileInChunks(sourceFile, encryptedFile, key, iv, chunkSize);
                decryptFileInChunks(encryptedFile, decryptedFile, key, iv, position, length,chunkSize);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
